function mxCellMarker(graph, validColor, invalidColor, hotspot)
{
	if (graph != null)
	{
		this.graph = graph;
		this.validColor = (validColor != null) ? validColor : mxConstants.DEFAULT_VALID_COLOR;
		this.invalidColor = (validColor != null) ? invalidColor : mxConstants.DEFAULT_INVALID_COLOR;
		this.hotspot = (hotspot != null) ? hotspot : mxConstants.DEFAULT_HOTSPOT;
		this.highlight = new mxCellHighlight(graph);
	}
};
mxCellMarker.prototype = new mxEventSource();
mxCellMarker.prototype.constructor = mxCellMarker;
mxCellMarker.prototype.graph = null;
mxCellMarker.prototype.enabled = true;
mxCellMarker.prototype.hotspot = mxConstants.DEFAULT_HOTSPOT;
mxCellMarker.prototype.hotspotEnabled = false;
mxCellMarker.prototype.validColor = null;
mxCellMarker.prototype.invalidColor = null;
mxCellMarker.prototype.currentColor = null;
mxCellMarker.prototype.validState = null;
mxCellMarker.prototype.markedState = null;
mxCellMarker.prototype.setEnabled = function(enabled)
{
	this.enabled = enabled;
};
mxCellMarker.prototype.isEnabled = function()
{
	return this.enabled;
};
mxCellMarker.prototype.setHotspot = function(hotspot)
{
	this.hotspot = hotspot;
};
mxCellMarker.prototype.getHotspot = function()
{
	return this.hotspot;
};
mxCellMarker.prototype.setHotspotEnabled = function(enabled)
{
	this.hotspotEnabled = enabled;
};
mxCellMarker.prototype.isHotspotEnabled = function()
{
	return this.hotspotEnabled;
};
mxCellMarker.prototype.hasValidState = function()
{
	return this.validState != null;
};
mxCellMarker.prototype.getValidState = function()
{
	return this.validState;
};
mxCellMarker.prototype.getMarkedState = function()
{
	return this.markedState;
};
mxCellMarker.prototype.reset = function()
{
	this.validState = null;

	if (this.markedState != null)
	{
		this.markedState = null;
		this.unmark();
	}
};
mxCellMarker.prototype.process = function(me)
{
	var state = null;

	if (this.isEnabled())
	{
		state = this.getState(me);
		var isValid = (state != null) ? this.isValidState(state) : false;
		var color = this.getMarkerColor(me.getEvent(), state, isValid);

		if (isValid)
		{
			this.validState = state;
		}
		else
		{
			this.validState = null;
		}

		if (state != this.markedState || color != this.currentColor)
		{
			this.currentColor = color;

			if (state != null && this.currentColor != null)
			{
				this.markedState = state;
				this.mark();
			}
			else if (this.markedState != null)
			{
				this.markedState = null;
				this.unmark();
			}
		}
	}
	return state;
};
mxCellMarker.prototype.mark = function()
{
	this.highlight.setHighlightColor(this.currentColor);
	this.highlight.highlight(this.markedState);
	this.fireEvent(mxEvent.MARK, new mxEventObject([this.markedState]));
};
mxCellMarker.prototype.unmark = function()
{
	this.mark();
};
mxCellMarker.prototype.isValidState = function(state)
{
	return true;
};
mxCellMarker.prototype.getMarkerColor = function(evt, state, isValid)
{
	return (isValid) ? this.validColor : this.invalidColor;
};
mxCellMarker.prototype.getState = function(me)
{
	var view = this.graph.getView();
	cell = this.getCell(me);
	var state = this.getStateToMark(view.getState(cell));
	return (state != null && this.intersects(state, me)) ? state : null;
};
mxCellMarker.prototype.getCell = function(me)
{
	return me.getCell();
};
mxCellMarker.prototype.getStateToMark = function(state)
{
	return state;
};
mxCellMarker.prototype.intersects = function(state, me)
{
	if (this.hotspotEnabled)
	{
		var point = mxUtils.convertPoint(this.graph.container, me.getX(), me.getY());
		return mxUtils.intersectsHotspot(state, point.x, point.y, this.hotspot, mxConstants.MIN_HOTSPOT_SIZE,
			mxConstants.MAX_HOTSPOT_SIZE);
	}
	return true;
};
mxCellMarker.prototype.destroy = function()
{
	this.graph.getView().removeListener(this.resetHandler);
	this.graph.getModel().removeListener(this.resetHandler);
};